package bingo.monitor.datasource.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import bingo.monitor.datasource.ConnectionInfo;
import bingo.monitor.datasource.ConnectionMonitor;


/**
 * Servlet implementation class MonitorReportServlet
 */
public class MonitorReportServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * Default constructor. 
	 */
	public MonitorReportServlet() {

	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doPost(request, response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

		Set<ConnectionInfo> connections = ConnectionMonitor.getMonitor().getConnectionInfos();
		
		//sorted by time
		TreeSet<ConnectionInfo> sortedConnections = new TreeSet<ConnectionInfo>(ConnectionComparator.instance);
		sortedConnections.addAll(connections);

		response.setCharacterEncoding("UTF-8");
		response.setContentType("text/html");
		PrintWriter out = response.getWriter();
		out.write("<html><head><title>Connection Monitor Report</title>");
		out.write("<meta http-equiv='content-type' content='text/html; charset=UTF-8'>");
		out.write("<script>function showDetail(info){document.getElementById('detail').innerHTML=info;}</script>");
		out.append("</script></head><body>");
		out.write("<button onclick='window.location.reload()'>refresh</button><br>");
		out.write("<table border=1 width=800>");
		out.write("<tr><td colspan='5'>Total connections opened : " + sortedConnections.size());
		out.write("</td></tr>");
		out.write("<tr><td>Index</td><td>DataSource</td><td>Open Time</td><td>Time Taken(ms)</td><td>StackTrace(StackDetail)</td></tr>");

		StringBuilder buff = new StringBuilder();
		int index = 1;
		int size = 20;
		for(ConnectionInfo info : sortedConnections){
			if(--size < 0) break;
			if(!info.isClosed()){
				long now = System.currentTimeMillis();
				long timeTaken = now - info.getOpenTime();

				buff.append("<tr>");
				buff.append("<td>").append(index++).append("</td>");
				buff.append("<td>datasource(").append(info.getDataSource()).append(")</td>");
				buff.append("<td>").append(toTimeString(info.getOpenTime())).append("</td>");
				buff.append("<td>").append(timeTaken).append("</td>");
				buff.append("<td onclick=\"showDetail('").append(stackTrace(info.getOpenStack())).append("');\" style='cursor:hand;'>Detail Message</td>");
				buff.append("</tr>");
			}
		}
		//
		buff.append("</table><br><br>########################################################## Detail Message ##########################################################<br>");
		buff.append("<div id='detail'></div>");		
		out.write(buff.toString());
		out.write("</body></html>");
	}

	private static String stackTrace(StackTraceElement[] trace){
		StringBuilder buff = new StringBuilder();

		for(int i=0;i<trace.length;i++){
			if(i > 3){
				StackTraceElement e = trace[i];
				buff.append("at ").append(e.getClassName()).append(".").append(e.getMethodName())
				.append("(").append(e.getFileName()).append(":").append(e.getLineNumber()).append(")<br>");
			}
		}

		return buff.toString();
	}

	private static String toTimeString(long time){
		Calendar c = Calendar.getInstance();
		c.setTimeInMillis(time);
		return new SimpleDateFormat("MM-dd HH:mm:ss.SSS").format(c.getTime());
	}

	private static class ConnectionComparator implements Comparator<ConnectionInfo>{

		private static ConnectionComparator instance = new ConnectionComparator();

		/* (non-Javadoc)
		 * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
		 */
		public int compare(ConnectionInfo o1, ConnectionInfo o2) {
			return o1.getOpenTime() > o2.getOpenTime() ? 1 : -1;
		}
	}
}
